﻿using System;
using System.Data;
using System.Text;
using Microsoft.SharePoint;
using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.ExceptionManagement;

using SPListNames = Kiiro.Common.Utility.Constants.SPListNames;
using ProjectFieldNames = Kiiro.Common.Utility.Constants.ProjectFieldNames;
using System.Collections.Generic;

namespace Kiiro.DataAccess
{
    public class ProjectsDA
    {
        #region Singleton
        private ProjectsDA ( )
        {
        }

        private static ProjectsDA instance = null;
        private static readonly object threadLock = new object ( );

        public static ProjectsDA Instance
        {
            get
            {
                lock ( threadLock )
                {
                    if ( instance == null )
                    {
                        instance = new ProjectsDA ( );
                    }
                }
                return instance;
            }
        }
        #endregion

        /// <summary>
        /// Gets a list of Project entities.
        /// </summary>
        /// <param name="projectIds">The list of project ids to get</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url</param>
        /// <param name="ifEmptyReturnAll">If set to true, returns ALL projects when projectIds list is null or empty</param>
        public List<Project> GetProjectsByIds ( List<int> projectIds, Guid siteCollectionId, string serverRelativeUrl, bool ifEmptyReturnAll )
        {
            List<Project> projects = new List<Project> ( );
            SPList list = null;

            using (SPWeb web = SPHelpers.GetPortalWeb(siteCollectionId, serverRelativeUrl))
            {
                list = web.Lists[SPListNames.Projects];

                if (list != null)
                {
                    SPQuery query = new SPQuery();

                    bool first = true;
                    if (projectIds != null && projectIds.Count > 0)
                    {
                        foreach (int projectId in projectIds)
                        {
                            if (!first) query.Query = "<Or>" + query.Query;
                            query.Query += "<Eq><FieldRef Name='ID'/><Value Type='Integer'>" + projectId + "</Value></Eq>";
                            if (!first) query.Query += "</Or>";

                            first = false;
                        }
                    }

                    if (ifEmptyReturnAll || (projectIds != null && projectIds.Count > 0))
                    {
                        if (!string.IsNullOrEmpty(query.Query))
                            query.Query = "<Where>" + query.Query + "</Where>";

                        query.Query = query.Query + "<OrderBy><FieldRef Name='" + Constants.ProjectFieldNames.Title + "' Ascending='True'/></OrderBy>";

                        SPListItemCollection listItems = list.GetItems(query);
                        if (listItems != null)
                        {
                            foreach (SPListItem listItem in listItems)
                            {
                                try
                                {
                                    projects.Add(SPDataHelpers.MakeProject(listItem));
                                }
                                catch (Exception ex)
                                {
                                    ExceptionManager.HandleException(ex, false);
                                }
                            }
                        }
                    }
                }
            }

            return projects;
        }

        public Project GetByServerRelativeWebUrl ( Guid siteCollectionId, string serverRelativeWebUrl )
        {
            Project project = null;

            // we do this in case serverRelativeWebUrl is pointing to an item inside the web and not to the web itself
            serverRelativeWebUrl = SPHelpers.GetServerRelativeWebUrl ( siteCollectionId, serverRelativeWebUrl );

            try
            {
                using ( SPWeb web = SPHelpers.GetPortalWeb ( siteCollectionId, serverRelativeWebUrl ) )
                {
                    StringBuilder queryText = new StringBuilder ( );
                    queryText.Append ( "<Where>" );
                    queryText.Append ( "  <Eq>" );
                    queryText.Append ( "    <FieldRef Name='" + ProjectFieldNames.ServerRelativeWebUrl + "'/>" );
                    queryText.Append ( "    <Value Type='Text'>" + serverRelativeWebUrl + "</Value>" );
                    queryText.Append ( "  </Eq>" );
                    queryText.Append ( "</Where>" );

                    SPQuery query = new SPQuery ( );
                    query.Query = queryText.ToString ( );

                    SPList list = web.Lists[SPListNames.Projects];

                    if ( list != null )
                    {
                        DataTable dataTable = list.GetItems ( query ).GetDataTable ( );

                        if ( dataTable != null && dataTable.Rows.Count > 0 )
                        {
                            project = SPDataHelpers.MakeProject ( dataTable.Rows[0] );
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return project;
        }
        
        public int GetNumberOfOpenProjects ( Guid siteCollectionId, string serverRelativeUrl )
        {
            int count = 0;

            try
            {
                using ( SPWeb web = SPHelpers.GetPortalWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    SPList list = web.Lists [ SPListNames.Projects ];

                    if ( list != null )
                    {
                        StringBuilder queryText = new StringBuilder ( );
                        queryText.Append ( "<Where>" );
                        queryText.Append ( "  <Neq>" );
                        queryText.Append ( "    <FieldRef Name='" + ProjectFieldNames.ProjectStatus + "'/>" );
                        queryText.Append ( "    <Value Type='Choice'>" + ProjectStatus.Closed.ToString ( ) + "</Value>" );
                        queryText.Append ( "  </Neq>" );
                        queryText.Append ( "</Where>" );

                        SPQuery query = new SPQuery ( );
                        query.ViewFields =
                            "<FieldRef Name='" + ProjectFieldNames.ItemId + "'  Nullable='TRUE'/>" +
                            "<FieldRef Name='" + ProjectFieldNames.ProjectStatus + "'  Nullable='TRUE'/>";
                        query.Query = queryText.ToString ( );

                        SPListItemCollection items = list.GetItems ( query );
                        if ( items != null )
                            count = items.Count;
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return count;
        }

        public Project Save ( Project project, Guid siteCollectionId, string serverRelativeUrl )
        {
            SPList list = null;
            SPListItem listItem = null;
            try
            {
                if ( project == null )
                    throw new Exception ( "Cannot SaveProject() when Project is null" );

                if ( project.EditType != EditType.Unchanged )
                {
                    using (SPWeb web = SPHelpers.GetPortalWeb(siteCollectionId, serverRelativeUrl))
                    {
                        list = web.Lists[SPListNames.Projects];

                        if (list != null)
                        {
                            #region Get Item
                            listItem = (project.EditType == EditType.Created) ? list.Folders.Add() : list.Folders.GetItemById(project.Id);

                            switch (project.EditType)
                            {
                                case EditType.Created:
                                    listItem[ProjectFieldNames.SiteCollectionId] = siteCollectionId;
                                    listItem[ProjectFieldNames.CreatedBy] = project.CreatedBy.Id;
                                    listItem[ProjectFieldNames.ModifiedBy] = project.CreatedBy.Id;
                                    listItem[ProjectFieldNames.CreatedDate] = DateTime.Now;
                                    listItem[ProjectFieldNames.ModifiedDate] = DateTime.Now;
                                    listItem [ ProjectFieldNames.ServerRelativeWebUrl ] = project.ServerRelativeWebUrl;
                                    listItem[ProjectFieldNames.IsSynched] = false;
                                    break;
                                case EditType.Updated:
                                    if (project.ModifiedBy != null && project.ModifiedBy.Id > 0)
                                        listItem[ProjectFieldNames.ModifiedBy] = project.ModifiedBy.Id;
                                    listItem[ProjectFieldNames.ModifiedDate] = DateTime.Now;
                                    break;
                                case EditType.Deleted:
                                default:
                                    break;
                            }
                            #endregion

                            if (project.EditType != EditType.Deleted)
                            {
                                #region Set Item Properties
                                if (listItem != null && project.EditType != EditType.Deleted)
                                {
                                    if (project.ActualWork >= 0)
                                        listItem[Constants.ProjectFieldNames.ActualWork] = project.ActualWork;

                                    if (project.ProjectedWork >= 0)
                                        listItem[Constants.ProjectFieldNames.ProjectedWork] = project.ProjectedWork;

                                    if (project.TotalWork >= 0)
                                        listItem[Constants.ProjectFieldNames.TotalWork] = project.TotalWork;

                                    if (!string.IsNullOrEmpty(project.Description))
                                        listItem[Constants.ProjectFieldNames.Description] = project.Description;

                                    if (!string.IsNullOrEmpty(project.Title))
                                        listItem[Constants.ProjectFieldNames.Title] = project.Title;

                                    if (!string.IsNullOrEmpty(project.SummaryNote))
                                        listItem[Constants.ProjectFieldNames.SummaryNote] = project.SummaryNote;
                                    else
                                        listItem[Constants.ProjectFieldNames.SummaryNote] = string.Empty;

                                    if (project.ProjectManagerIds.Count > 0)
                                        listItem[Constants.ProjectFieldNames.ProjectManagerIds] = FormattingHelpers.ListOfIntsToFieldText(project.ProjectManagerIds);
                                    else
                                        listItem[Constants.ProjectFieldNames.ProjectManagerIds] = string.Empty;

                                    if (project.DiscussionStats.Count > 0)
                                        listItem[Constants.ProjectFieldNames.DiscussionStats] = FormattingHelpers.ListOfStringsToFieldText(project.DiscussionStats);

                                    if (project.DocumentStats.Count > 0)
                                        listItem[Constants.ProjectFieldNames.DocumentStats] = FormattingHelpers.ListOfStringsToFieldText(project.DocumentStats);

                                    if (project.IssueStats.Count > 0)
                                        listItem[Constants.ProjectFieldNames.IssueStats] = FormattingHelpers.ListOfStringsToFieldText(project.IssueStats);
                                    else
                                        listItem[Constants.ProjectFieldNames.IssueStats] = string.Empty;

                                    if (project.TaskStats.Count > 0)
                                        listItem[Constants.ProjectFieldNames.TaskStats] = FormattingHelpers.ListOfStringsToFieldText(project.TaskStats);
                                    else
                                        listItem[Constants.ProjectFieldNames.TaskStats] = string.Empty;

                                    if (project.EndDate != null && project.EndDate != DateTime.MinValue)
                                        listItem[Constants.ProjectFieldNames.EndDate] = project.EndDate;
                                    else
                                        listItem[Constants.ProjectFieldNames.EndDate] = null;

                                    if (project.StartDate != null && project.StartDate != DateTime.MinValue)
                                        listItem[Constants.ProjectFieldNames.StartDate] = project.StartDate;
                                    else
                                        listItem[Constants.ProjectFieldNames.StartDate] = null;

                                    listItem[Constants.ProjectFieldNames.PlanDirty] = project.PlanDirty;

                                    listItem[Constants.ProjectFieldNames.TasksDirty] = project.TasksDirty;

                                    listItem[Constants.ProjectFieldNames.ProjectStatus] = project.ProjectStatus;

                                    listItem[Constants.ProjectFieldNames.TimeMetric] = project.TimeMetric;

                                    listItem[Constants.ProjectFieldNames.LastUpdatedSummaryNote] = project.LastUpdatedSummaryNote;

                                    listItem[Constants.ProjectFieldNames.IsWPSandboxActivated] = project.IsWPSandboxActivated;
                                    listItem[Constants.ProjectFieldNames.WPSandboxNavText] = project.WPSandboxNavText;

                                    //if ( !string.IsNullOrEmpty ( project.ProjectPlanFileUrl ) )
                                        listItem [ ProjectFieldNames.ProjectPlanFileUrl ] = project.ProjectPlanFileUrl;

                                    SPDataHelpers.PopulateCustomFieldsInListItemFromEntity(listItem, project);
                                }
                                #endregion
                            }

                            #region Update/Delete Item
                            try
                            {
                                list.ParentWeb.AllowUnsafeUpdates = true;
                                if (project.EditType == EditType.Deleted)
                                {
                                    list.Folders.DeleteItemById(listItem.ID);
                                }
                                else
                                {
                                    listItem.Update();
                                    listItem = list.Folders.GetItemById(listItem.ID);

                                    project = SPDataHelpers.MakeProject(listItem);
                                }
                            }
                            catch (Exception ex)
                            {
                                ExceptionManager.HandleException(ex, true);
                            }
                            finally
                            {
                                list.ParentWeb.AllowUnsafeUpdates = false;
                            }
                            #endregion
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }
            return project;
        }

        public void ProjectIsSynched ( Project project, Guid siteCollectionId, string serverRelativeUrl )
        {
            SPList list = null;
            SPListItem listItem = null;

            if (project.EditType == EditType.Updated)
            {
                using (SPWeb web = SPHelpers.GetPortalWeb(siteCollectionId, serverRelativeUrl))
                {
                    list = web.Lists[SPListNames.Projects];

                    if (list != null)
                    {
                        listItem = list.Folders.GetItemById(project.Id);

                        if (listItem != null)
                        {
                            if (project.ModifiedBy != null && project.ModifiedBy.Id > 0)
                                listItem[ProjectFieldNames.ModifiedBy] = project.ModifiedBy.Id;
                            listItem[ProjectFieldNames.ModifiedDate] = DateTime.Now;

                            listItem[ProjectFieldNames.IsSynched] = true;
                            listItem[ProjectFieldNames.PlanDirty] = true;

                            try
                            {
                                list.ParentWeb.AllowUnsafeUpdates = true;
                                listItem.Update();
                                project = SPDataHelpers.MakeProject(listItem);
                            }
                            catch (Exception ex)
                            {
                                ExceptionManager.HandleException(ex, true);
                            }
                            finally
                            {
                                list.ParentWeb.AllowUnsafeUpdates = false;
                            }
                        }
                    }
                }
            }
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.DataAccess/ProjectsDA.cs $
 * 
 * 22    2/08/10 5:04p Camerons
 * 
 * 21    1/25/10 1:17p Camerons
 * 
 * 20    1/12/10 12:02p Camerons
 * 
 * 19    26/11/09 10:35a Camerons
 * 
 * 18    17/11/09 6:46p Camerons
 * 
 * 17    30/10/09 6:21p Camerons
 * 
 * 16    10/27/09 5:53p Adamw
 * accomodations for moving plan file to document library:
 * -moved saving of plan out of ProjectsDA and into DocumentModel -->
 * DocumentDA
 * -added call to save project plan file to document library from
 * ProjectsModel
 * -changed New/Edit Project pages to pass in Attachment collection
 * 
 * 15    10/26/09 3:12p Adamw
 * Case 295, elevated uploading of project plan for team members who are
 * not admins but are PMs
 * 
 * 14    30/09/09 9:17a Shafia
 * 
 * 13    29/09/09 12:40p Shafia
 * Implemented WebPart at project level
 * 
 * 12    23/09/09 4:32p Shafia
 * 
 * 11    22/09/09 6:03p Camerons
 * Code changes to support creating user on demand - version 1.1.x.x
 * 
 * 10    31/08/09 12:17p Shafia
 * assgined the LastUpdatedSummaryNote
 * 
 * 9     17/08/09 10:41a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/